#include "ch32x035.h"
#include "stdint.h"
#include "stdio.h"
#include "DevicesOPA.h"
#include "DevicesADC.h"


static uint16_t st_usADCDmaDatas[ADC1_SAMPLING_NUMBER][ADC1_SAMPLING_CHANNEL] = {0};


static void vADC1DMAInit(void)
{
    DMA_InitTypeDef DMA_InitStructure = {0};

    /* enable DMA0 clock */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    /* initialize DMA single data mode */
    DMA_DeInit(DMA1_Channel1);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->RDATAR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)st_usADCDmaDatas;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = ADC1_SAMPLING_NUMBER * ADC1_SAMPLING_CHANNEL;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);

    ADC_DMACmd(ADC1, ENABLE);

    /* enable DMA channel */
    DMA_Cmd(DMA1_Channel1, ENABLE);
}

void vADCInit(void)
{
    ADC_InitTypeDef  ADC_InitStructure = {0};
    GPIO_InitTypeDef GPIO_InitStructure = {0};

    /* enable GPIOx clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    /* enable ADC clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    /* OPA 模拟放大输出通道 */
    vOpaInit();

    /* config ADC clock */
    ADC_CLKConfig(ADC1, ADC_CLK_Div6);

    ADC_DeInit(ADC1);
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = ADC1_SAMPLING_CHANNEL;
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_VOLTAGE_OUT,     ADC_DMA_VOLTAGE_OUT,        ADC1_SAMPLE_TIME);
    ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_CURRENT_OUT,     ADC_DMA_CURRENT_OUT,        ADC1_SAMPLE_TIME);

    vADC1DMAInit();

    /* enable ADC interface */
    ADC_Cmd(ADC1, ENABLE);
    /* ADC software trigger enable */
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

/*!
    \brief      ADC dma channel
    \param[in]  none
    \param[out] none
    \retval     none
*/
float fADCGetDMAValue(AdcDmaChannelEnum enumChannel)
{
#if (ADC1_SAMPLING_NUMBER < 3)
    return ((int32_t)st_usADCDmaDatas[0][enumChannel - 1] * (3.3f / 4095.0f));

#else
    uint32_t uiValueSum = 0;
    uint16_t *pDatasHand = st_usADCDmaDatas[enumChannel - 1];
    uint16_t usValueMax = 0, usValueMin = 0xFFFF, usValueNow, i;

    if(enumChannel > ADC1_SAMPLING_CHANNEL)
        return 0.0f;

    for(i = 0; i < ADC1_SAMPLING_NUMBER; ++i)
    {
        usValueNow  = *pDatasHand;
        uiValueSum += usValueNow;

        pDatasHand += ADC1_SAMPLING_CHANNEL;

        /* 找到最大与最小值 */
        usValueMax = (usValueMax < usValueNow) ? usValueNow : usValueMax;
        usValueMin = (usValueMin > usValueNow) ? usValueNow : usValueMin;
    }

    uiValueSum -= usValueMax + usValueMin;

    return ((float)uiValueSum / (ADC1_SAMPLING_NUMBER - 2) * (3.3f / 4095.0f));

#endif
}

/*!
    \brief      ADC dma channel
    \param[in]  none
    \param[out] none
    \retval     none
*/
int32_t iADCGetDMAValue(AdcDmaChannelEnum enumChannel)
{
#if (ADC1_SAMPLING_NUMBER < 3)
    return ((int32_t)st_usADCDmaDatas[0][enumChannel - 1] * 3300) / 4095;

#else
    uint32_t uiValueSum = 0;
    uint16_t *pDatasHand = st_usADCDmaDatas[enumChannel - 1];
    uint16_t usValueMax = 0, usValueMin = 0xFFFF, usValueNow, i;

    if(enumChannel > ADC1_SAMPLING_CHANNEL)
        return 0.0f;

    for(i = 0; i < ADC1_SAMPLING_NUMBER; ++i)
    {
        usValueNow  = *pDatasHand;
        uiValueSum += usValueNow;

        pDatasHand += ADC1_SAMPLING_CHANNEL;

        /* 找到最大与最小值 */
        usValueMax = (usValueMax < usValueNow) ? usValueNow : usValueMax;
        usValueMin = (usValueMin > usValueNow) ? usValueNow : usValueMin;
    }

    uiValueSum -= usValueMax + usValueMin;

    return (uiValueSum * 3300) / (4095 * (ADC1_SAMPLING_NUMBER - 2));

#endif
}

/*!
    \brief      ADC channel sample
    \param[in]  none
    \param[out] none
    \retval     none
*/
float fADCGetChannelValue(ADC_TypeDef *ADCx, uint8_t channel, uint32_t uiCnt)
{
    uint32_t uiValueSum = 0, i = 0;
    uint16_t usValueNow = 0, usValueMax = 0, usValueMin = 0xFFFF;

    /* ADC regular channel config */
    ADC_RegularChannelConfig(ADCx, channel, 1, ADC_SampleTime_11Cycles);

    /* 切换通道后，丢弃第一次转换的数据 */
    /* wait the end of conversion flag */
    while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC));
    /* clear the end of conversion flag */
    ADC_ClearFlag(ADCx, ADC_FLAG_EOC);
    /* get regular channel sample value */
    ADC_GetConversionValue(ADCx);

    for(i = 0; i < uiCnt; ++i)
    {
        /* wait the end of conversion flag */
        while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC));
        /* clear the end of conversion flag */
        ADC_ClearFlag(ADCx, ADC_FLAG_EOC);
        /* get regular channel sample value */
        usValueNow = ADC_GetConversionValue(ADCx);

        uiValueSum += usValueNow;;

        /* 找到最大与最小值 */
        usValueMax = (usValueMax < usValueNow) ? usValueNow : usValueMax;
        usValueMin = (usValueMin > usValueNow) ? usValueNow : usValueMin;
    }

    /* 去除最大与最小值 */
    uiValueSum -= (usValueMax + usValueMin);

    return ((float)uiValueSum / (uiCnt - 2) * (3.3f / 4095.0f));
}
